package com.alibaba.jvm.sandbox.core;

import com.alibaba.jvm.sandbox.api.Information;
import com.alibaba.jvm.sandbox.core.util.FeatureCodec;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.io.File;
import java.nio.charset.Charset;
import java.util.*;

// core启动配置
public class CoreConfigure {

    // jvm-sandbox版本号
    private static final String RASP_VERSION = "1.3.0"; // 理论上，sandbox-agent、sandbox-spy逻辑不会在变化了，这个版本号最好在core中定义

    // 各种key，用来从agent传递的字符串获取值
    private static final String KEY_NAMESPACE = "namespace"; // 在 AgentLauncher 有默认值

    private static final String KEY_USERNAME = "username"; // 默认登陆用户名，用户attach时传递

    private static final String KEY_PASSWORD = "password";// 默认登陆密码，用户attach时传递

    private static final String KEY_ENCRYPTION = "encryption";

    private static final String DEFAULT_VAL_ENCRYPTION = ""; //默认为空，不加密，密码示例：rasp-server1.0.0

    private static final String KEY_SANDBOX_HOME = "sandbox_home";

    private static final String KEY_LAUNCH_MODE = "mode";

    private static final String KEY_SERVER_IP = "server.ip";

    private static final String KEY_SERVER_PORT = "server.port";

    private static final String KEY_SERVER_CHARSET = "server.charset";

    private static final String KEY_SYSTEM_MODULE_LIB_PATH = "system_module";

    private static final String KEY_USER_MODULE_LIB_PATH = "user_module";

    private static final String KEY_PROVIDER_LIB_PATH = "provider";

    private static final String KEY_CFG_LIB_PATH = "cfg";

    private static final String KEY_UNSAFE_ENABLE = "unsafe.enable";

    private static final FeatureCodec codec = new FeatureCodec(';', '=');

    private final Map<String, String> featureMap = new LinkedHashMap<String, String>();

    private CoreConfigure(final String featureString) {
        final Map<String, String> featureMap = toFeatureMap(featureString);
        this.featureMap.putAll(featureMap);
    }

    private Map<String, String> toFeatureMap(String featureString) {
        return codec.toMap(featureString);
    }

    private static volatile CoreConfigure instance;

    // 在AgentLauncher中被反射调用
    public static CoreConfigure toConfigure(final String featureString) {
        return instance = new CoreConfigure(featureString);
    }

    public static CoreConfigure getInstance() {
        return instance;
    }

    // 获取容器的命名空间
    public String getNamespace() {
        return featureMap.get(KEY_NAMESPACE);
    }

    // 获取系统模块加载路径
    public String getSystemModuleLibPath() {
        return featureMap.get(KEY_SYSTEM_MODULE_LIB_PATH); // sandbox/module/
    }

    // 获取用户模块加载路径
    public String getUserModuleLibPath() {
        return featureMap.get(KEY_USER_MODULE_LIB_PATH);
    }

    // TODO 获取用户模块加载文件集合 /sandbox/run/<pid>/xxx.jar
    public synchronized File[] getUserModuleLibFiles() {
        final Collection<File> foundModuleJarFiles = new LinkedHashSet<File>();
        String path = getUserModuleLibPath();
        final File fileOfPath = new File(path);
        assert fileOfPath.isDirectory();
        // 路径下全部jar包
        foundModuleJarFiles.addAll(FileUtils.listFiles(new File(path), new String[]{"jar"}, false)); // 不递归查找
        return GET_USER_MODULE_LIB_FILES_CACHE = foundModuleJarFiles.toArray(new File[]{});
    }

    // 用户模块加载文件/目录缓存集合
    private volatile File[] GET_USER_MODULE_LIB_FILES_CACHE = null;

    // 从缓存中获取用户模块加载文件/目录
    public File[] getUserModuleLibFilesWithCache() {
        if (null != GET_USER_MODULE_LIB_FILES_CACHE) {
            return GET_USER_MODULE_LIB_FILES_CACHE;
        } else {
            return getUserModuleLibFiles();
        }
    }

    // 获取配置文件加载路径(日志配置文件)
    public String getCfgLibPath() {
        return featureMap.get(KEY_CFG_LIB_PATH);
    }

    @Override
    public String toString() {
        return codec.toString(featureMap);
    }

    // 是否以attach模式启动
    private boolean isLaunchByAttachMode() {
        return BooleanUtils.toBoolean(featureMap.get(KEY_LAUNCH_MODE));
    }

    // 获取沙箱的启动模式
    public Information.Mode getLaunchMode() {
        if (isLaunchByAttachMode()) {
            return Information.Mode.ATTACH;
        }
        return Information.Mode.AGENT;
    }

    // 是否启用Unsafe功能
    public boolean isEnableUnsafe() {
        return BooleanUtils.toBoolean(featureMap.get(KEY_UNSAFE_ENABLE));
    }

    // 获取沙箱安装目录
    public String getJvmSandboxHome() {
        return featureMap.get(KEY_SANDBOX_HOME);
    }

    // 获取服务器绑定IP
    public String getServerIp() {
        return StringUtils.isNotBlank(featureMap.get(KEY_SERVER_IP))
                ? featureMap.get(KEY_SERVER_IP)
                : "127.0.0.1";
    }

    // 获取服务器端口
    public int getServerPort() {
        return NumberUtils.toInt(featureMap.get(KEY_SERVER_PORT), 0);
    }

    // 获取沙箱内部服务提供库目录
    public String getProviderLibPath() {
        return featureMap.get(KEY_PROVIDER_LIB_PATH);
    }

    // 获取服务器编码
    public Charset getServerCharset() {
        try {
            return Charset.forName(featureMap.get(KEY_SERVER_CHARSET));
        } catch (Exception cause) {
            return Charset.defaultCharset();
        }
    }

    // 获取加密密钥
    public String getEncryption() {
        String encryption = featureMap.get(KEY_ENCRYPTION);
        return StringUtils.isNotBlank(encryption)
                ? encryption
                : DEFAULT_VAL_ENCRYPTION;
    }

    // 获取登陆用户名称
    public String getUsername() {
        return featureMap.get(KEY_USERNAME); //一定有
    }

    // 获取登陆用户密码
    public String getPassword() {
        return featureMap.get(KEY_PASSWORD); //一定有
    }

    // 设置加密密钥
    public void setEncryption(String encryption) {
        featureMap.put(KEY_ENCRYPTION, encryption);
    }

    // 设置登陆用户名称
    public void setUsername(String username) {
        featureMap.put(KEY_USERNAME, username);
    }

    // 设置登陆用户密码
    public void setPassword(String password) {
        featureMap.put(KEY_PASSWORD, password);
    }

    // 获取版本号
    public String getVersion() {
        return RASP_VERSION;
    }

}
